package uk.ac.ebi.bioinvindex.dao.ejb3;

import org.hibernate.criterion.Restrictions;
import uk.ac.ebi.bioinvindex.dao.QueryParameter;
import uk.ac.ebi.bioinvindex.dao.StudyDAO;
import uk.ac.ebi.bioinvindex.model.impl.MaterialImpl;
import uk.ac.ebi.bioinvindex.model.impl.StudyImpl;
import uk.ac.ebi.bioinvindex.model.impl.term.MaterialRoleImpl;
import uk.ac.ebi.bioinvindex.model.impl.term.PropertyImpl;
import uk.ac.ebi.bioinvindex.model.impl.term.PropertyRole;
import uk.ac.ebi.bioinvindex.model.impl.term.PropertyValueImpl;

import javax.persistence.EntityManager;
import java.util.Collection;
import java.util.List;

/**
 * User: Nataliya Sklyar (nsklyar@ebi.ac.uk)
 * Date: Jun 22, 2007
 */
public class StudyEJB3DAO extends AnnotatableEJB3DAO<StudyImpl> implements StudyDAO {

	public StudyEJB3DAO() {
		super(StudyImpl.class);
	}

	public StudyEJB3DAO(EntityManager entityManager) {
		super(StudyImpl.class, entityManager);
	}

	public List<MaterialImpl> getMaterialsOfType(Long studyId, MaterialRoleImpl materialRole) {

		List result = entityManager.createQuery("select node.material " +
				"from MaterialNodeImpl node, MaterialImpl material " +
				"where " +
				"node.study.id = :studyId " +
				"and node.material = material.id " +
				"and material.type = :sourceType").
				setParameter("studyId", studyId).
				setParameter("sourceType", materialRole).getResultList();

		return result;
	}

	public List<StudyImpl> findByProperty(QueryParameter query) {

		//ToDo: check if propertyName is a valid property
		return getSession().createCriteria(StudyImpl.class)
				.add(Restrictions.like(query.getParameterName(), query.getValue()))
				.list();

	}

	/**
	 * Filters a collection of Studies by its property value.
	 *
	 * @param ids a Collection of IDs of studies to be filtered
	 * @param queryParameter
	 * @return
	 */
	public List<StudyImpl> filterByProperty(Collection<Long> ids, QueryParameter queryParameter) {

		//ToDo: check if propertyName is a valid property
		return getSession().createCriteria(StudyImpl.class)
				.add(Restrictions.like(queryParameter.getParameterName(), queryParameter.getValue()))
				.add(Restrictions.in("id", ids))
				.list();
	}


	/* Corresponding SQL query
SELECT distinct Property.id, property.name
FROM
NODE, Property_value, property
where
node.study_id = 100 and
node.material_id=property_value.material_id and
property_value.property_id = property.id
and property.role=1
	 */
	public List<PropertyImpl> getFactorsForStudy(Long studyId) {
		return entityManager.createQuery("SELECT distinct p \n" +
				"FROM MaterialNodeImpl node, PropertyValueImpl pv, PropertyImpl p \n" +
				"WHERE\n" +
				"node.study.id =:studyId " +
				"AND node.material.id=pv.material.id " +
				"AND pv.type = p.id\n" +
				"and p.role =:role")
				.setParameter("studyId", studyId)
				.setParameter("role", PropertyRole.FACTOR)
				.getResultList();
	}

	public List<StudyImpl> findByAssayType(String assayTypeName) {
		return getSession().createCriteria(StudyImpl.class)
				.createCriteria("assays")
				.createCriteria("technology")
				.add(Restrictions.eq("name", assayTypeName))
				.list();
	}

	public List<StudyImpl> filterByAssayType(Collection<Long> ids, String assayTypeName) {
			return getSession().createCriteria(StudyImpl.class)
					.createCriteria("assays")
					.createCriteria("type")
					.add(Restrictions.eq("name", assayTypeName))
					.add(Restrictions.in("id", ids))
					.list();
		}

	public List<PropertyValueImpl> getValuesOfProperty(Long studyId, String propertyName) {
		return entityManager.createQuery("SELECT distinct pv \n" +
				"FROM MaterialNodeImpl node, PropertyValueImpl pv, PropertyImpl p \n" +
				"WHERE\n" +
				"node.study.id =:studyId " +
				"AND node.material.id=pv.material.id " +
				"AND pv.type = p.id\n" +
				"and p.value =:name")
				.setParameter("studyId", studyId)
				.setParameter("name", propertyName)
				.getResultList();
	}

	public List<PropertyValueImpl> getValuesOfProperty(String propertyName) {
		return entityManager.createQuery("SELECT distinct pv \n" +
				"FROM PropertyValueImpl pv, PropertyImpl p \n" +
				"WHERE\n" +
				"pv.type = p.id\n" +
				"and p.value =:name")
				.setParameter("name", propertyName)
				.getResultList();
	}

	public List<StudyImpl> filterByPropertyNameValue(String propertyName, String propertyValue) {
		return entityManager.createQuery("SELECT distinct study \n" +
				"FROM StudyImpl study, MaterialNodeImpl node, PropertyValueImpl pv, PropertyImpl p \n" +
				"WHERE\n" +
				"study.id = node.study.id " +
				"AND node.material.id=pv.material.id " +
				"AND pv.type = p.id\n" +
				"AND pv.value =:value\n" +
				"and p.value =:name")
				.setParameter("name", propertyName)
				.setParameter("value", propertyValue)
				.getResultList();
	}


//	public List<Study> filterByProperty(List<Study> studies, QueryParameter queryParameter) {
//
//		String queryString = "were this." + queryParameter.getParameterName()
//				+ " =\'" + queryParameter.getValue() + "\'";
//
//		System.out.println("queryString = " + queryString);
//
//		return getSession().createFilter(studies, queryString).list();
//	}
}
